/******************************************************************************

    Simple Authentication and Authorisation System (SAAS)

    pkt-group.c

    Copyright (C) 2011  Josh Goes


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    If you require a mailing address for this software, please send your
    mail to the following address:
        SAAS
        GPO Box 2973
        BRISBANE QLD 4001
        AUSTRALIA

******************************************************************************/



#include "saas-build.h"

#include <string.h>
#include <stdlib.h>


uint16_t pkt_req_gid_to_groupname( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , uint32_t gid )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];
	uint32_t  *ptr = (uint32_t *) &payload;

	memset( payload , 0 , sizeof( payload ) );
	*ptr = u32tonet( gid );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GID_TO_GROUPNAME , payload , 4 );

	return SAAS_OP_SUCCESS;
}



uint16_t pkt_req_groupname_to_gid( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , const uint8_t *groupname , uint8_t groupname_len )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];

	memset( payload , 0 , sizeof( payload ) );
	payload[0] = groupname_len;
	memcpy( payload + 1 , groupname , groupname_len );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUPNAME_TO_GID , payload , groupname_len + 1 );

	return SAAS_OP_SUCCESS;
}



uint16_t pkt_req_group_info_by_gid( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , uint32_t gid )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];
	uint32_t  *ptr = (uint32_t *) &payload;

	memset( payload , 0 , sizeof( payload ) );
	*ptr = u32tonet( gid );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_BY_GID , payload , 4 );

	return SAAS_OP_SUCCESS;
}


uint16_t pkt_req_group_info_by_groupname( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , const uint8_t *groupname , uint8_t groupname_len )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];

	memset( payload , 0 , sizeof( payload ) );
	payload[0] = groupname_len;
	memcpy( payload + 1 , groupname , groupname_len );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_BY_GROUPNAME , payload , groupname_len + 1 );

	return SAAS_OP_SUCCESS;
}


uint16_t pkt_req_group_info_with_members_by_gid( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , uint32_t gid )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];
	uint32_t  *ptr = (uint32_t *) &payload;

	memset( payload , 0 , sizeof( payload ) );
	*ptr = u32tonet( gid );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GID , payload , 4 );

	return SAAS_OP_SUCCESS;
}


uint16_t pkt_req_group_info_with_members_by_groupname( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , const uint8_t *groupname , uint8_t groupname_len )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];

	memset( payload , 0 , sizeof( payload ) );
	payload[0] = groupname_len;
	memcpy( payload + 1 , groupname , groupname_len );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GROUPNAME , payload , groupname_len + 1 );

	return SAAS_OP_SUCCESS;
}


uint16_t pkt_req_group_info_with_all_members_by_gid( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , uint32_t gid )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];
	uint32_t  *ptr = (uint32_t *) &payload;

	memset( payload , 0 , sizeof( payload ) );
	*ptr = u32tonet( gid );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GID , payload , 4 );

	return SAAS_OP_SUCCESS;
}


uint16_t pkt_req_group_info_with_all_members_by_groupname( saas_t *inst , uint32_t *trans_id , uint8_t *pkt , uint16_t *pkt_len , const uint8_t *groupname , uint8_t groupname_len )
{
	uint8_t  payload[SAAS_MAX_PKT_LEN];

	memset( payload , 0 , sizeof( payload ) );
	payload[0] = groupname_len;
	memcpy( payload + 1 , groupname , groupname_len );

	// now we call pkt_pack to pack it altogether into a single packet.
	pkt_req( inst , trans_id , pkt , pkt_len , SAAS_MAGIC_REQ , SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GROUPNAME , payload , groupname_len + 1 );

	return SAAS_OP_SUCCESS;
}

















uint16_t pkt_resp_gid_to_groupname( saas_t *inst , uint32_t trans_id , uint8_t *pkt , uint16_t pkt_len , uint8_t **groupname )
{
	uint16_t ret = pkt_resp( inst , trans_id , pkt , pkt_len );
	if ( ret != SAAS_OP_SUCCESS )
		return ret;

	pkt_hdr_t *hdr = (pkt_hdr_t *) pkt;
	if ( hdr->type == SAAS_PKT_TYPE_GID_TO_GROUPNAME && hdr->payload_len >= 2 )
	{
		// the right kind of response we're looking for.
		uint16_t *fret          = (uint16_t *)  pkt + ( sizeof( pkt_hdr_t ) / 2 );
		uint8_t  *groupname_len = (uint8_t *)   pkt + sizeof( pkt_hdr_t ) + 4;
		*groupname = malloc( *groupname_len + 1 );
		if ( *groupname == NULL )
			return SAAS_OP_MEM_ERROR;
		memset( *groupname , 0 , *groupname_len + 1 );
		memcpy( *groupname , pkt + sizeof( pkt_hdr_t ) + 5 , *groupname_len );
		return *fret;
	}

	return SAAS_OP_DECRYPT_ERROR;
}




uint16_t pkt_resp_groupname_to_gid( saas_t *inst , uint32_t trans_id , uint8_t *pkt , uint16_t pkt_len , uint32_t *gid )
{
	uint16_t ret = pkt_resp( inst , trans_id , pkt , pkt_len );
	if ( ret != SAAS_OP_SUCCESS )
		return ret;

	pkt_hdr_t *hdr = (pkt_hdr_t *) pkt;
	if ( hdr->type == SAAS_PKT_TYPE_GROUPNAME_TO_GID && hdr->payload_len >= 8 )
	{
		// the right kind of response we're looking for.
		uint16_t  *fret = (uint16_t  *)  pkt + ( sizeof( pkt_hdr_t ) / 2 );
		*gid  = u32fromnet( *( (uint32_t *)  pkt + ( sizeof( pkt_hdr_t ) / 4 ) + 1 ) );
		return *fret;
	}

	return SAAS_OP_DECRYPT_ERROR;
}



uint16_t pkt_resp_group_info( saas_t *inst , uint32_t trans_id , uint8_t *pkt , uint16_t pkt_len , saas_group_info_t **group_info )
{
	uint8_t  *lol;
	saas_group_info_t *gi;
	uint32_t  roffset, woffset, k;
	uint32_t  rsz = 0, sz = 0;

	uint16_t  ret = pkt_resp( inst , trans_id , pkt , pkt_len );
	if ( ret != SAAS_OP_SUCCESS )
		return ret;

	pkt_hdr_t *hdr = (pkt_hdr_t *) pkt;
	switch ( hdr->type )
	{
		case SAAS_PKT_TYPE_GROUP_INFO_BY_GID:
		case SAAS_PKT_TYPE_GROUP_INFO_BY_GROUPNAME:
		case SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GID:
		case SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GROUPNAME:
		case SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GID:
		case SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GROUPNAME:
			break;

		default:
			return SAAS_OP_DECRYPT_ERROR;
	}

	if ( hdr->payload_len >= 2 )
	{
		// first size the malloc to be the same as saas_group_info_t + pkt_len
		// so that the varying lengths of groupnames, etc are covered for.
		sz = sizeof( saas_group_info_t ) + pkt_len;
		lol = malloc( sz );
		if ( lol == NULL )
			return SAAS_OP_MEM_ERROR;
		memset( lol , 0 , sz );
		gi = (saas_group_info_t *) lol;

		// set the read offset to start at the start of the payload.
		roffset = sizeof( pkt_hdr_t );
		// and set the write offset to the end of the saas group info struct.
		woffset = sizeof( saas_group_info_t );

		// capture the result of the operation.
		memcpy( &ret  ,  pkt + roffset  ,  2 );  roffset += 2;
		ret = u16fromnet( ret );
		if ( ret != SAAS_OP_SUCCESS )
		{
			free( lol );
			return ret;
		}

		// capture the number of members in this response.
		memcpy( &gi->num_members , pkt + roffset , 2 );  roffset += 2;
		gi->num_members = u16fromnet( gi->num_members );

		// capture the GID.
		memcpy( &gi->gid , pkt + roffset , 4 );  roffset += 4;
		gi->gid = u32fromnet( gi->gid );

		// capture the groupname.
		memcpy( &gi->groupname_len , pkt + roffset , 1 );  roffset += 1;
		gi->groupname = (char *) lol + woffset;
		strncpy( gi->groupname , (char *) pkt + roffset , gi->groupname_len );  roffset += gi->groupname_len;
		woffset += gi->groupname_len + 1;

		// if there are any members, load 'em in.
		if ( gi->num_members > 0 )
		{
			// at this point we'll need to extend our malloc to include
			// all the member info.
			rsz  = sizeof( saas_group_member_t * ) * ( gi->num_members + 1 );
			rsz += sizeof( saas_group_member_t ) * gi->num_members;
			// the groupname/username lengths would have been covered by the pkt_len/sz malloc
			// above.
			lol = realloc( lol , sz + rsz );
			if ( lol == NULL )
				return SAAS_OP_MEM_ERROR;
			gi = (saas_group_info_t *) lol;
			// blank out the EXTENSION ONLY, not the stuff we've
			// already populated.
			memset( lol + sz , 0 , rsz );

			uint8_t  name_len;

			// set up the double-pointer array...
			gi->members = (saas_group_member_t **) ( (uint8_t *) lol + woffset );
			woffset += sizeof( saas_group_member_t * ) * ( gi->num_members + 1 );

			// set up room for each member element
			for ( k = 0 ; k < gi->num_members ; k++ )
			{
				gi->members[k] = (saas_group_member_t *) ( (uint8_t *) lol + woffset );
				woffset += sizeof( saas_group_member_t );
			}
			for ( k = 0 ; k < gi->num_members ; k++ )
			{
				// copy the member type.
				gi->members[k]->type = *( (uint8_t *) pkt + roffset );   roffset += 1;

				// copy the member ID.
				gi->members[k]->id = *( (uint32_t *) ( (uint8_t *) pkt + roffset ) );   roffset += 4;
				gi->members[k]->id = u32fromnet( gi->members[k]->id );

				// copy the member name.
				memcpy( &name_len , pkt + roffset , 1 );   roffset += 1;
				gi->members[k]->name = (char *) lol + woffset;  woffset += name_len + 1;
				strncpy( gi->members[k]->name , (char *) pkt + roffset , name_len );  roffset += name_len;
			}
		}

		// and finally map the malloc address back to the calling function.
		*group_info = gi;

		return ret;
	}

	return SAAS_OP_DECRYPT_ERROR;
}


